﻿using System;
using Csla;
using BizControl.Library.BusinessObjects.Activities;
using BizControl.Library.BusinessObjects.People;
using System.ComponentModel.DataAnnotations;
using Csla.Rules.CommonRules;
using BizControl.DalLinq;
using Csla.Data;
using System.Data.Linq;
using BizControl.Library.Security;
using BizControl.Resources;

namespace BizControl.Library.BusinessObjects.Comments
{
  [Serializable()]
  public class CommentBO : BusinessBase<CommentBO>
  {
    #region Business Methods

    private static readonly PropertyInfo<Guid> CommentIdProperty = RegisterProperty<Guid>(c => c.CommentId);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"CommentCommentIdRequiredPropertyError")]
    public Guid CommentId
    {
      get { return GetProperty(CommentIdProperty); }
      private set { SetProperty(CommentIdProperty, value); }
    }

    private static readonly PropertyInfo<string> TextProperty = RegisterProperty<string>(c => c.Text, null);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"CommentTextRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"CommentTextProperty")]
    public string Text
    {
      get { return GetProperty(TextProperty); }
      set { SetProperty(TextProperty, value); }
    }

    private static readonly PropertyInfo<Guid?> ActivityProperty = RegisterProperty<Guid?>(c => c.ActivityId);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"ActivityRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"ActivityIdProperty")]
    Guid? ActivityId
    {
      get { return GetProperty(ActivityProperty); }
      set { SetProperty(ActivityProperty, value); }
    }

    private static readonly PropertyInfo<ObjectPriority> PriorityProperty = RegisterProperty<ObjectPriority>(c => c.Priority, null, ObjectPriority.Normal);
    [Display(ResourceType = typeof(PropertiesNames), Name = @"CommentPriorityProperty")]
    public int Priority
    {
      get { return GetPropertyConvert<ObjectPriority, int>(PriorityProperty); }
      set { SetPropertyConvert<ObjectPriority, int>(PriorityProperty, value); }
    }

    #region Common properties

    private static readonly PropertyInfo<bool> IsDeletedFieldProperty = RegisterProperty<bool>(c => c.IsDeletedField, null, false);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"IsDeletedRequiredError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"IsDeletedFieldProperty")]
    public bool IsDeletedField
    {
      get { return GetProperty(IsDeletedFieldProperty); }
      private set { SetProperty(IsDeletedFieldProperty, value); }
    }

    private static readonly PropertyInfo<PersonInfo> CreatedByProperty = RegisterProperty<PersonInfo>(c => c.CreatedBy);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"CreatedByRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"CreatedByProperty")]
    public PersonInfo CreatedBy
    {
      get { return GetProperty(CreatedByProperty); }
      private set { SetProperty(CreatedByProperty, value); }
    }

    private static readonly PropertyInfo<DateTime> DateProperty = RegisterProperty<DateTime>(c => c.Date);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"CreatedOnRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"CreatedOnProperty")]
    public DateTime Date
    {
      get { return GetProperty(DateProperty); }
      private set { SetProperty(DateProperty, value); }
    }

    private static readonly PropertyInfo<DateTime> LastChangedProperty = RegisterProperty<DateTime>(c => c.LastChanged);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"LastChangedRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"LastChangedProperty")]
    public DateTime LastChanged
    {
      get { return GetProperty(LastChangedProperty); }
      private set { SetProperty(LastChangedProperty, value); }
    }

    private static readonly PropertyInfo<PersonInfo> LastChangedByProperty = RegisterProperty<PersonInfo>(c => c.LastChangedBy);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"LastChangedByRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"LastChangedByProperty")]
    public PersonInfo LastChangedBy
    {
      get { return GetProperty(LastChangedByProperty); }
      private set { SetProperty(LastChangedByProperty, value); }
    }

    private static readonly PropertyInfo<byte[]> TimeStampProperty = RegisterProperty<byte[]>(c => c.TimeStamp);
    private byte[] TimeStamp
    {
      get { return GetProperty(TimeStampProperty); }
      set { SetProperty(TimeStampProperty, value); }
    }

    #endregion

    internal void LoadData(Comment commentDB)
    {
      if (commentDB == null) return;
      CommentId = commentDB.CommentId;
      Text = commentDB.Text;
      Priority = commentDB.Priority ?? (int)ObjectPriority.Normal;

      // Common properties
      CreatedBy = new PersonInfo(commentDB.CreatedByRef);
      LastChangedBy = new PersonInfo(commentDB.LastChangedByRef);

      Date = commentDB.Date;
      LastChanged = commentDB.LastChanged;

      IsDeletedField = commentDB.IsDeleted;
      TimeStamp = commentDB.TimeStamp.ToArray();
    }

    private void LinkCommentWithActivity(ActivityBO activity)
    {
      ActivityId = activity.ActivityId;
    }

    #endregion

    #region Business Rules

    protected override void AddBusinessRules()
    {
      base.AddBusinessRules();
    }

    #endregion

    #region  Data Access

    private void Child_Create(ActivityBO activity)
    {
      if (activity == null) throw new ArgumentNullException(ExceptionsMessages.ActivityNullReference);
      var currentUser = SecurityChecks.GetCurrentUser();
      using (BypassPropertyChecks)
      {
        CommentId = Guid.NewGuid();
        LinkCommentWithActivity(activity);
        CreatedBy = new PersonInfo(currentUser);
        LastChangedBy = new PersonInfo(currentUser);
        Date = DateTime.Now;
      }
      base.Child_Create();
    }

    private void Child_Fetch(Comment data, ActivityBO activity)
    {
      if (activity == null) throw new ArgumentNullException(ExceptionsMessages.ActivityNullReference);
      using (BypassPropertyChecks)
      {
        LinkCommentWithActivity(activity);
        LoadData(data);
      }
    }

    private void Child_Insert()
    {
      using (var ctx = ContextManager<BusinessControl2DataContext>.GetManager(Database.BizControlDB))
      {
        Binary lastTimeStamp = null;
        LastChanged = DateTime.Now;
        using (BypassPropertyChecks)
        {
          ctx.DataContext.AddComment(
            CommentId,
            ActivityId,
            CreatedBy == null || CreatedBy.IsEmpty() ? (Guid?)null : CreatedBy.Id,
            Text,
            Priority,
            IsDeletedField,
            Date,
            LastChanged,
            LastChangedBy == null || LastChangedBy.IsEmpty() ? (Guid?)null : LastChangedBy.Id,
            ref lastTimeStamp);
          TimeStamp = lastTimeStamp.ToArray();
        }
      }
    }

    private void Child_Update()
    {
      using (var ctx = ContextManager<BusinessControl2DataContext>.GetManager(Database.BizControlDB))
      {
        if (IsSelfDirty)
        {
          Binary lastTimeStamp = null;
          LastChangedBy = new PersonInfo(SecurityChecks.GetCurrentUser());
          LastChanged = DateTime.Now;
          using (BypassPropertyChecks)
          {
            ctx.DataContext.UpdateComment(
              CommentId,
              Text,
              Priority,
              IsDeletedField,
              LastChanged,
              LastChangedBy == null || LastChangedBy.IsEmpty() ? (Guid?)null : LastChangedBy.Id,
              TimeStamp,
              ref lastTimeStamp);
            TimeStamp = lastTimeStamp.ToArray();
          }
        }
      }
    }

    #endregion

    #region  Factory Methods

    internal static CommentBO NewComment(ActivityBO activity)
    {
      return Csla.DataPortal.CreateChild<CommentBO>(activity);
    }

    internal static CommentBO GetComment(Comment data, ActivityBO activity)
    {
      return Csla.DataPortal.FetchChild<CommentBO>(data, activity);
    }

    private CommentBO()
    { /* require use of factory methods */ }

    #endregion  

  }
}
